package tools

import (
	"encoding/binary"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

type Audio struct {
	WavFileName string
	WavBytes    []byte
}

// AddWavHeader 为原始音频数据添加WAV文件头
func (a *Audio) AddWavHeader(audioBytes []byte, numChannels, sampleRate, bitsPerSample int) error {
	// 验证参数
	if numChannels <= 0 || sampleRate <= 0 || bitsPerSample <= 0 {
		return fmt.Errorf("invalid parameters: channels=%d, sampleRate=%d, bitsPerSample=%d",
			numChannels, sampleRate, bitsPerSample)
	}

	if audioBytes == nil {
		return fmt.Errorf("audio data is nil")
	}

	// 计算所需参数
	dataSize := len(audioBytes)
	byteRate := sampleRate * numChannels * bitsPerSample / 8
	blockAlign := numChannels * bitsPerSample / 8

	// 创建缓冲区
	buf := make([]byte, 0, 44+len(audioBytes)) // WAV头固定44字节

	// RIFF块
	buf = append(buf, 'R', 'I', 'F', 'F')
	buf = binary.LittleEndian.AppendUint32(buf, uint32(36+dataSize)) // 文件总大小-8
	buf = append(buf, 'W', 'A', 'V', 'E')

	// fmt子块
	buf = append(buf, 'f', 'm', 't', ' ')
	buf = binary.LittleEndian.AppendUint32(buf, 16) // fmt块大小
	buf = binary.LittleEndian.AppendUint16(buf, 1)  // 音频格式(PCM=1)
	buf = binary.LittleEndian.AppendUint16(buf, uint16(numChannels))
	buf = binary.LittleEndian.AppendUint32(buf, uint32(sampleRate))
	buf = binary.LittleEndian.AppendUint32(buf, uint32(byteRate))
	buf = binary.LittleEndian.AppendUint16(buf, uint16(blockAlign))
	buf = binary.LittleEndian.AppendUint16(buf, uint16(bitsPerSample))

	// data子块
	buf = append(buf, 'd', 'a', 't', 'a')
	buf = binary.LittleEndian.AppendUint32(buf, uint32(dataSize))

	// 添加PCM数据
	buf = append(buf, audioBytes...)

	// 保存文件
	err := os.WriteFile(a.WavFileName, buf, 0666)
	if err != nil {
		return fmt.Errorf("failed to write WAV file: %w", err)
	}

	a.WavBytes = buf
	return nil
}

// PlayWav 播放WAV音频文件
func (a *Audio) PlayWav() error {
	if a.WavFileName == "" {
		return fmt.Errorf("WAV file name is empty")
	}

	// 检查文件是否存在
	if _, err := os.Stat(a.WavFileName); os.IsNotExist(err) {
		return fmt.Errorf("WAV file does not exist: %s", a.WavFileName)
	}

	// 检查ffplay是否可用
	_, err := exec.LookPath("ffplay")
	if err != nil {
		return fmt.Errorf("ffplay not found in PATH, please install ffmpeg: %w", err)
	}

	// 播放音频文件
	cmd := exec.Command("ffplay", "-autoexit", "-nodisp", a.WavFileName)
	// -autoexit: 播放完自动退出
	// -nodisp: 无图形界面（纯音频）

	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to play audio: %w", err)
	}

	return nil
}

// PlayWavAsync 异步播放WAV音频文件
func (a *Audio) PlayWavAsync() error {
	if a.WavFileName == "" {
		return fmt.Errorf("WAV file name is empty")
	}

	// 检查文件是否存在
	if _, err := os.Stat(a.WavFileName); os.IsNotExist(err) {
		return fmt.Errorf("WAV file does not exist: %s", a.WavFileName)
	}

	// 检查ffplay是否可用
	_, err := exec.LookPath("ffplay")
	if err != nil {
		return fmt.Errorf("ffplay not found in PATH, please install ffmpeg: %w", err)
	}

	// 异步播放音频文件
	cmd := exec.Command("ffplay", "-autoexit", "-nodisp", a.WavFileName)

	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to start audio playback: %w", err)
	}

	// 不等待播放完成，直接返回
	return nil
}

// SaveWav 保存WAV字节数据到文件
func (a *Audio) SaveWav(filename string) error {
	if len(a.WavBytes) == 0 {
		return fmt.Errorf("no WAV data to save")
	}

	err := os.WriteFile(filename, a.WavBytes, 0666)
	if err != nil {
		return fmt.Errorf("failed to save WAV file: %w", err)
	}

	return nil
}

// LoadWav 从文件加载WAV数据
func (a *Audio) LoadWav(filename string) error {
	data, err := os.ReadFile(filename)
	if err != nil {
		return fmt.Errorf("failed to read WAV file: %w", err)
	}

	a.WavFileName = filename
	a.WavBytes = data
	return nil
}

// GetDuration 计算音频时长（秒）
func (a *Audio) GetDuration(numChannels, sampleRate, bitsPerSample int) float64 {
	if len(a.WavBytes) <= 44 { // WAV header is 44 bytes
		return 0
	}

	bytesPerSample := bitsPerSample / 8
	samples := (len(a.WavBytes) - 44) / (numChannels * bytesPerSample)
	duration := float64(samples) / float64(sampleRate)

	return duration
}

// ValidateWav 验证WAV文件格式
func (a *Audio) ValidateWav() error {
	if len(a.WavBytes) < 44 {
		return fmt.Errorf("invalid WAV file: too small")
	}

	// 检查RIFF头
	if string(a.WavBytes[0:4]) != "RIFF" {
		return fmt.Errorf("invalid WAV file: missing RIFF header")
	}

	// 检查WAVE标识
	if string(a.WavBytes[8:12]) != "WAVE" {
		return fmt.Errorf("invalid WAV file: missing WAVE identifier")
	}

	// 检查fmt块
	if string(a.WavBytes[12:16]) != "fmt " {
		return fmt.Errorf("invalid WAV file: missing fmt chunk")
	}

	// 检查data块
	if string(a.WavBytes[36:40]) != "data" {
		// 尝试查找data块（在一些WAV文件中可能有其他块）
		found := false
		for i := 12; i < len(a.WavBytes)-8; i++ {
			if string(a.WavBytes[i:i+4]) == "data" {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("invalid WAV file: missing data chunk")
		}
	}

	return nil
}

// IsWav 检查字节数据是否为有效的WAV格式
func IsWav(data []byte) bool {
	if len(data) < 12 {
		return false
	}

	return string(data[0:4]) == "RIFF" && string(data[8:12]) == "WAVE"
}

// GetWavInfo 获取WAV文件信息
func (a *Audio) GetWavInfo() (map[string]interface{}, error) {
	if err := a.ValidateWav(); err != nil {
		return nil, err
	}

	info := make(map[string]interface{})

	// 获取文件大小
	fileSize := binary.LittleEndian.Uint32(a.WavBytes[4:8])
	info["fileSize"] = fileSize + 8 // 包含RIFF和大小字段

	// 获取格式块信息
	fmtSize := binary.LittleEndian.Uint32(a.WavBytes[16:20])
	info["fmtSize"] = fmtSize

	audioFormat := binary.LittleEndian.Uint16(a.WavBytes[20:22])
	info["audioFormat"] = audioFormat

	numChannels := binary.LittleEndian.Uint16(a.WavBytes[22:24])
	info["numChannels"] = numChannels

	sampleRate := binary.LittleEndian.Uint32(a.WavBytes[24:28])
	info["sampleRate"] = sampleRate

	byteRate := binary.LittleEndian.Uint32(a.WavBytes[28:32])
	info["byteRate"] = byteRate

	blockAlign := binary.LittleEndian.Uint16(a.WavBytes[32:34])
	info["blockAlign"] = blockAlign

	bitsPerSample := binary.LittleEndian.Uint16(a.WavBytes[34:36])
	info["bitsPerSample"] = bitsPerSample

	// 获取数据块信息
	dataSize := binary.LittleEndian.Uint32(a.WavBytes[40:44])
	info["dataSize"] = dataSize

	// 计算时长
	duration := float64(dataSize) / float64(byteRate)
	info["duration"] = duration

	return info, nil
}

// ConvertToMp3 将WAV文件转换为MP3格式（需要ffmpeg）
func (a *Audio) ConvertToMp3(mp3FileName string) error {
	if a.WavFileName == "" {
		return fmt.Errorf("no WAV file loaded")
	}

	// 检查文件是否存在
	if _, err := os.Stat(a.WavFileName); os.IsNotExist(err) {
		return fmt.Errorf("WAV file does not exist: %s", a.WavFileName)
	}

	// 检查ffmpeg是否可用
	_, err := exec.LookPath("ffmpeg")
	if err != nil {
		return fmt.Errorf("ffmpeg not found in PATH: %w", err)
	}

	// 执行转换
	cmd := exec.Command("ffmpeg", "-i", a.WavFileName, "-f", "mp3", mp3FileName)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to convert WAV to MP3: %s, %w", string(output), err)
	}

	return nil
}

// SupportedAudioFormats 返回支持的音频格式列表
func SupportedAudioFormats() []string {
	return []string{"wav", "mp3", "aac", "flac", "ogg"}
}

// HasAudioPlayer 检查系统是否有可用的音频播放器
func HasAudioPlayer() (string, bool) {
	players := []string{"ffplay", "vlc", "mplayer"}

	for _, player := range players {
		if _, err := exec.LookPath(player); err == nil {
			return player, true
		}
	}

	return "", false
}

// PlayWith 指定播放器播放音频
func (a *Audio) PlayWith(player string) error {
	if a.WavFileName == "" {
		return fmt.Errorf("no audio file specified")
	}

	// 检查文件是否存在
	if _, err := os.Stat(a.WavFileName); os.IsNotExist(err) {
		return fmt.Errorf("audio file does not exist: %s", a.WavFileName)
	}

	// 检查播放器是否可用
	_, err := exec.LookPath(player)
	if err != nil {
		return fmt.Errorf("%s not found in PATH: %w", player, err)
	}

	var cmd *exec.Cmd

	// 根据播放器类型设置参数
	switch strings.ToLower(player) {
	case "ffplay":
		cmd = exec.Command(player, "-autoexit", "-nodisp", a.WavFileName)
	case "vlc":
		cmd = exec.Command(player, "--intf", "dummy", "--play-and-exit", a.WavFileName)
	default:
		cmd = exec.Command(player, a.WavFileName)
	}

	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to play audio with %s: %w", player, err)
	}

	return nil
}
